Skip to main content

DefaultDrawingsSnapshotsRepo

  • Stores snapshots (undo and redo steps) of drawings as scripts. A snapshot is saved when changing the color of a drawing, moving its point, changing the line width, or changing the font size.
  • Snapshots are parsed and placed in the com.devexperts.dxcharts.lib.domain.drawings.AllDrawingsSnapshot class.
  • The repository includes methods for:
    • adding a new snapshot - addSnapshot
    • checking for the existence of a previous snapshot - hasPreviousStep
    • checking for the existence of a next snapshot - hasNextStep
    • going to the previous snapshot - previousStep
    • going to the next snapshot - nextStep
    • checking for the presence of at least one snapshot - canClear
    • returning the current version of the set snapshot - currentVersion

Default implementation of the repository:

/**
* Default implementation of [DrawingsSnapshotsRepo].
*
* This class provides a default implementation of the [DrawingsSnapshotsRepo] interface.
*
* @property snapshots List of all drawing snapshots.
* @property getMaxVersion Callback function to get the maximum snapshot index.
* @property setMaxVersion Callback function to set the maximum snapshot index.
* @property getCurrentVersionCallback Callback function to get the current snapshot index.
* @property incrementAndGetCurrentVersion Callback function to increment and get the current snapshot index.
* @property decrementAndGetCurrentVersion Callback function to decrement and get the current snapshot index.
*/
open class DefaultDrawingsSnapshotsRepo(
private val snapshots: MutableList<AllDrawingsSnapshot>,
@get:Synchronized private val getMaxVersion: () -> Int,
@get:Synchronized private val setMaxVersion: (Int) -> Unit,
@get:Synchronized private val getCurrentVersionCallback: () -> Int,
@get:Synchronized private val incrementAndGetCurrentVersion: () -> Int,
@get:Synchronized private val decrementAndGetCurrentVersion: () -> Int,
) : DrawingsSnapshotsRepo {
/**
* Initializes the repository with an empty snapshot.
*/
init {
snapshots.add(0, AllDrawingsSnapshot.Empty)
}
/**
* Method to add a new snapshot.
*
* When adding a new snapshot [snapshot], if it differs from the last emitted:
* - the drawing is added to the [snapshots] list,
* - the current version variable is incremented,
* - the maximum version variable is set to the current version.
*
* Accordingly, if a snapshot with index 3 was set, with a maximum version of 7, then when adding a new snapshot versions 4, 5, 6, 7 will be erased,
* and a new snapshot with version 4 is recorded instead, current = 4, max = 4.
*
* @param snapshot The snapshot to add.
*/
@Synchronized
override fun addSnapshot(snapshot: AllDrawingsSnapshot) {
val newList = snapshot.drawingsList
val oldList = snapshots[getCurrentVersionCallback()].drawingsList
if (!newList.cmp(oldList)) {
snapshots.add(incrementAndGetCurrentVersion(), snapshot)
setMaxVersion(getCurrentVersionCallback())
}
}
/**
* Returns true if the version of the snapshot is not equal to 0 - it is possible to go back to the previous snapshot, otherwise false.
*
* @return True if the previous step is available, otherwise false.
*/
@Synchronized
override fun hasPreviousStep(): Boolean {
return getCurrentVersionCallback() != 0
}
/**
* Returns true if the version of the snapshot is not equal to the maximum - it is possible to move to the next snapshot, otherwise false.
*
* @return True if the next step is available, otherwise false.
*/
@Synchronized
override fun hasNextStep(): Boolean {
return getCurrentVersionCallback() != getMaxVersion()
}
/**
* Returns true if the current snapshot is not empty - it is possible to clear all drawings, otherwise false.
*
* @return True if clear is possible, otherwise false.
*/
@Synchronized
override fun canClear(): Boolean {
return snapshots[getCurrentVersionCallback()] != AllDrawingsSnapshot.Empty
}
/**
* Sets the previous snapshot as the current one and returns it.
*
* If the current snapshot is the first one, returns null.
*
* @return Previous snapshot or null.
*/
@Synchronized
override fun previousStep(): AllDrawingsSnapshot? {
return if (getCurrentVersionCallback() != 0) {
snapshots[decrementAndGetCurrentVersion()]
} else {
null
}
}
/**
* Sets the next snapshot as the current one and returns it.
*
* If the current snapshot is the last one, returns null.
*
* @return Next snapshot or null.
*/
@Synchronized
override fun nextStep(): AllDrawingsSnapshot? {
return if (getCurrentVersionCallback() != getMaxVersion()) {
snapshots[incrementAndGetCurrentVersion()]
} else {
null
}
}
/**
* Returns the version of the current snapshot.
*
* @return The version of the current snapshot.
*/
@Synchronized
override fun currentVersion(): Int {
return getCurrentVersionCallback()
}
}
/**
* Method for comparing two lists of drawings based on properties:
* - id,
* - keyPoints,
* - type,
* - properties.line.lineWidth,
* - properties.text.textSize,
* - properties.line.lineColor,
* - properties.background.fillStyle,
* - properties.text.textBg,
* - properties.textValue
* as well as their size.
*
* @return True if the lists are equal, otherwise false.
*/
private fun DrawingsList.cmp(other: DrawingsList): Boolean {
val list1 = this.list
val list2 = other.list
if (list1 == null || list2 == null) {
return list1 == null && list2 == null
}
if (list1.size != list2.size) {
return false
}
list1.forEachIndexed { index, drawingObject ->
val equals = (drawingObject.id == list2[index].id
&& drawingObject.keyPoints == list2[index].keyPoints
&& drawingObject.type == list2[index].type
&& drawingObject.properties?.line?.lineWidth == list2[index].properties?.line?.lineWidth
&& drawingObject.properties?.text?.textSize == list2[index].properties?.text?.textSize
&& drawingObject.properties?.line?.lineColor == list2[index].properties?.line?.lineColor
&& drawingObject.properties?.background?.fillStyle == list2[index].properties?.background?.fillStyle
&& drawingObject.properties?.text?.textBg == list2[index].properties?.text?.textBg
&& drawingObject.properties?.textValue == list2[index].properties?.textValue)
if (!equals) {
return false
}
}
return true
}

Implementation of the default repository for local storage:

/**
* Local storage implementation of [DrawingsSnapshotsRepo].
*
* This class provides a local storage implementation of the [DrawingsSnapshotsRepo] interface,
* storing drawing snapshots locally with support for navigation and clearing.
*
* @constructor Creates a LocalStorageDefaultDrawingsSnapshotsRepo.
*/
class LocalStorageDefaultDrawingsSnapshotsRepo : DrawingsSnapshotsRepo {
/**
* The maximum snapshot version.
*/
private var maxVersion: Int = 0
/**
* The current snapshot version.
*/
private val currentVersion = AtomicInteger(0)
/**
* The list of all drawing snapshots.
*/
private val snapshots = ArrayList<AllDrawingsSnapshot>()
/**
* The default repository instance using local storage.
*/
private val defaultRepo = DefaultDrawingsSnapshotsRepo(
getMaxVersion = ::maxVersion,
setMaxVersion = ::maxVersion::set,
getCurrentVersionCallback = currentVersion::get,
incrementAndGetCurrentVersion = currentVersion::incrementAndGet,
decrementAndGetCurrentVersion = currentVersion::decrementAndGet,
snapshots = snapshots
)
/**
* Method to add a new snapshot.
*
* @param snapshot The snapshot to add.
*/
override fun addSnapshot(snapshot: AllDrawingsSnapshot) {
defaultRepo.addSnapshot(snapshot)
}
/**
* Checks if there is a previous step available.
*
* @return True if a previous step is available, otherwise false.
*/
override fun hasPreviousStep(): Boolean {
return defaultRepo.hasPreviousStep()
}
/**
* Checks if there is a next step available.
*
* @return True if a next step is available, otherwise false.
*/
override fun hasNextStep(): Boolean {
return defaultRepo.hasNextStep()
}
/**
* Checks if clearing is possible.
*
* @return True if clearing is possible, otherwise false.
*/
override fun canClear(): Boolean {
return defaultRepo.canClear()
}
/**
* Moves to the previous step and returns the corresponding snapshot.
*
* @return The previous snapshot, or null if not available.
*/
override fun previousStep(): AllDrawingsSnapshot? {
return defaultRepo.previousStep()
}
/**
* Moves to the next step and returns the corresponding snapshot.
*
* @return The next snapshot, or null if not available.
*/
override fun nextStep(): AllDrawingsSnapshot? {
return defaultRepo.nextStep()
}
/**
* Retrieves the version of the current snapshot.
*
* @return The version of the current snapshot.
*/
override fun currentVersion(): Int {
return defaultRepo.currentVersion()
}
}